延續前面的文章,再了解了 DragTarget 的用法後,今天希望可以做出一個元件,draggableButton 在拖入 target 時能在 target 相應的位置中顯示按鈕,一個可以讓我們自訂按鈕位置的 Frame 。
我們需要找到一個 Widget 可以滿足我們的需求,可以任意擺放位置的元件, Stack 剛好可以達成,透過 children 屬性中添加 Positioned.fromRect
在 stack 中添加兩個 Positioned 當作參考,這個範例中我們可以發現只要在 children 中添加元件就能符合我們的需求,能夠自訂位置
class Frame extends StatefulWidget {
@override
State<StatefulWidget> createState() => FrameState() ;
}
class FrameState extends State<Frame> {
@override
Widget build(BuildContext context) {
//定義兩個按鈕
var draggableBtn1 = RaisedButton(child: Text("1"),onPressed: (){},);
var draggableBtn2= RaisedButton(child: Text("2"),onPressed: (){},);
return Stack(
fit: StackFit.expand,//expand 會去符合父類別的大小
children: <Widget>[
Positioned.fill(child: Container(color: Colors.grey,)) ,
Positioned.fromRect(
rect: Rect.fromCenter(
center: Offset(100 , 100) ,//決定中心點的位置
width: 100 ,height: 100),
child: draggableBtn1
),
Positioned.fromRect(
rect: Rect.fromCenter(
center: Offset(210 , 100) ,
width: 100 ,height: 100),
child: draggableBtn2
)
],
) ;
}
}
範例圖示
修改一下上面的部分
class Frame extends StatefulWidget {
Frame({
Key key //增加 key 的傳入
}):super(key:key) ;
@override
State<StatefulWidget> createState() => FrameState() ;
}
class FrameState extends State<Frame> {
final List<DraggableInfo> data = List(); //存放 DraggableInfo 的 list
addData(DraggableInfo info) { //增加資料的方法
if (!data.contains(info)) {
data.add(info);
}
}
@override
Widget build(BuildContext context) {
//利用 list generate 與 data 的資料來產生 children
List<Widget> children = List.generate(data.length, (index) {
var draggableBtn = RaisedButton(
child: Text(data[index].text) ,
onPressed: (){},
);
return Positioned.fromRect(
rect: Rect.fromCenter(
center: Offset(data[index].dx,data[index].dy),
width: 100, height: 100),
child: draggableBtn
);
});
//設定背景
children.insert(0,
Positioned.fill(
child: Container(
color: Colors.grey,
)
)
);
return Stack(
fit: StackFit.expand,
children:children,
) ;
}
}
新增一個顯示 target 的 StatefulWidget
GlobalKey<FrameState> _frameGlobalKey = GlobalKey();
DragTarget<DraggableInfo>(
builder: (context,data,_){
return Frame(key: _frameGlobalKey,) ;
},
onAccept: (data){
setState(() {
_frameGlobalKey.currentState.addData(data);
});
},
);
DraggableInfo 新增一個 setOffset 的方法
class DraggableInfo{
...
...
setOffset(double dx, double dy) {
this.dx = dx;
this.dy = dy;
}
..
}
DraggableButtonState 內修改
class DraggableButtonState extends State<DraggableButton>{
...
...
...
var draggable = Draggable<DraggableInfo>(
child: sizeBtn,
feedback: Opacity(
opacity: 0.5,
child: sizeBtn
),
childWhenDragging:sizeBtn,
data: widget.data,
onDragEnd: (detail){
//當拖曳結束時修改 draggableIndo 內的 dx ,dy
widget.data.setOffset(detail.offset.dx, detail.offset.dy);
},
);
return draggable ;
}
圖示範例
完成後就能夠把按扭拖曳至frame中不過位子好像還不太正確,下一篇就來解決這個問題吧~